package main

import "fmt"

/*
在 Go 中接口是一种抽象类型，是一组方法的集合，里面只声明方法，而没有任何数据成员。

而在 Go 中实现一个接口也不需要显式的声明，只需要其他类型实现了接口中所有的方法，就是实现了这个接口
*/

// PaymentMethod 接口定义了支付方法的基本操作
type PayMethod interface {
	Account
	//这意味着实现 PayMethod 的类型，必须同时实现 GetBalance() 和 Pay() 两个方法。
	Pay(amount int) bool
}

type Account interface {
	GetBalance() int
}

// CreditCard 结构体实现 PaymentMethod 接口
type CreditCard struct {
	balance int
	limit   int
}

// CreditCard结构体实现PayMethod接口，就必须同时实现Account interface的方法
func (c *CreditCard) Pay(amount int) bool {
	if c.balance+amount <= c.limit {
		c.balance += amount
		fmt.Printf("信用卡支付成功: %d\n", amount)
		return true
	}
	fmt.Println("信用卡支付失败: 超出额度")
	return false
}

func (c *CreditCard) GetBalance() int {
	return c.balance
}

// DebitCard 结构体实现 PaymentMethod 接口
type DebitCard struct {
	balance int
}

func (d *DebitCard) Pay(amount int) bool {
	if d.balance >= amount {
		d.balance -= amount
		fmt.Printf("借记卡支付成功: %d\n", amount)
		return true
	}
	fmt.Println("借记卡支付失败: 余额不足")
	return false
}

func (d *DebitCard) GetBalance() int {
	return d.balance
}

// 使用 PaymentMethod 接口的函数
func purchaseItem(p PayMethod, price int) {
	if p.Pay(price) {
		fmt.Printf("购买成功，剩余余额: %d\n", p.GetBalance())
	} else {
		fmt.Println("购买失败")
	}
}

func main() {

	//接口的实现类,直接用接口类型作为变量时，赋值必须是类型的指针。
	creditCard := &CreditCard{balance: 0, limit: 1000}
	debitCard := &DebitCard{balance: 500}

	fmt.Println("使用信用卡购买:")
	purchaseItem(creditCard, 800)

	fmt.Println("\n使用借记卡购买:")
	purchaseItem(debitCard, 300)

	fmt.Println("\n再次使用借记卡购买:")
	purchaseItem(debitCard, 300)

	iphone := Iphone{phoneNum: "13798489587", msg: "hello world"}
	//	iphone.sendMessage()
	userPhone(&iphone, "你好", "13798489587")
}

type Landline interface {
	call(string)
}

type Phone interface {
	Landline
	message(string)
}

type Iphone struct {
	phoneNum string
	msg      string
}

func (p *Iphone) call(s string) {
	fmt.Printf("call my num: %v\n", s)
	//	panic("implement me")
}

func (p *Iphone) message(s string) {
	fmt.Printf("send me msg: %v\n", s)
	//	panic("implement me")
}

func (p *Iphone) sendMessage() {
	fmt.Printf("send message: %v\n", p.msg)
}

func userPhone(p Phone, msg string, num string) {
	p.message(msg)
	p.call(num)
}
